package com.vdong.redis.data.core.json.ops.impl;

import com.vdong.redis.data.core.json.DBExecutor;
import com.vdong.redis.data.core.json.FastJsonRedisTemplate;
import com.vdong.redis.data.core.json.ops.FastJsonHashOperations;
import com.vdong.redis.data.core.json.ops.impl.OperationsAware;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ScanOptions;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * ops覆盖类，可提供原先ops没有的方法
* @author <a href="mailto:zhudelie@zuozh.com">zhudelie</a>
* @version 
* @since JDK 1.6
* create on 2017年3月31日
* Copyright 2017 ZZJR All Rights Reserved.
*
*/
public class FastJsonHashOperationsImpl<K,HK,HV> extends OperationsAware<K, Object> implements FastJsonHashOperations<K,HK,HV> {
	HashOperations ops;
	public FastJsonHashOperationsImpl(HashOperations ops, FastJsonRedisTemplate<K,Object> template){
		super(template);
		this.ops = ops;
	}
	/**
	 * 删除hashkey
	 */
	
	public Long delete(K key, Object... hashKeys) {
		// TODO Auto-generated method stub
		return ops.delete(key, hashKeys);
	}
	/**
	 * 包含hashkey
	 */
	
	public Boolean hasKey(K key, Object hashKey) {
		// TODO Auto-generated method stub
		return ops.hasKey(key, hashKey);
	}
	/**
	 * 根据hashkey得到value
	 */
	
	public HV get(K key, Object hashKey) {
		// TODO Auto-generated method stub
		return (HV) ops.get(key, hashKey);
	}
	/**
	 * 根据多个hashkey得到多个value
	 */
	
	public List<HV> multiGet(K key, Collection<HK> hashKeys) {
		// TODO Auto-generated method stub
		return ops.multiGet(key, hashKeys);
	}
	/**
	 * 指定key自增指定大小
	 */
	
	public Long increment(K key, HK hashKey, long delta) {
		// TODO Auto-generated method stub
		return ops.increment(key, hashKey, delta);
	}
	/**
	 * 指定key自增指定大小
	 */
	
	public Double increment(K key, HK hashKey, double delta) {
		// TODO Auto-generated method stub
		return ops.increment(key, hashKey, delta);
	}
	/**
	 * 得到所有hashkey
	 */
	
	public Set<HK> keys(K key) {
		// TODO Auto-generated method stub
		return ops.keys(key);
	}
	/**
	 * 得到个数
	 */
	
	public Long size(K key) {
		// TODO Auto-generated method stub
		return ops.size(key);
	}
	/**
	 * 设置多个值
	 */
	
	public void putAll(K key, Map<? extends HK,? extends HV> m) {
		ops.putAll(key, m);
	}
	/**
	 * 设置值
	 */
	
	public void put(K key, HK hashKey, HV value) {
		ops.put(key, hashKey, value);
	}
	/**
	 * 设置值,如果该值不存在的话
	 */
	
	public Boolean putIfAbsent(K key, HK hashKey, HV value) {
		// TODO Auto-generated method stub
		return ops.putIfAbsent(key, hashKey, value);
	}
	/**
	 * 得到所有值
	 */
	
	public List<HV> values(K key) {
		// TODO Auto-generated method stub
		return ops.values(key);
	}
	/**
	 * 得到所有key和值
	 */
	
	public Map<HK, HV> entries(K key) {
		// TODO Auto-generated method stub
		return ops.entries(key);
	}

	
	public Cursor<Entry<HK, HV>> scan(K key, ScanOptions options) {
		// TODO Auto-generated method stub
		return ops.scan(key, options);
	}


	
	
	public void put(K key, HK hashKey, HV value, DBExecutor<HV> db) {
		put(key, hashKey, value, db, null, null);
	}
	public HV get(K key, HK hashKey,DBExecutor<HV> db) {
		return get(key,hashKey,db,null,null);
	}
	/**
	 * 根据hashkey，获得指定类型的值
	 * @param key
	 * @param hashKey
	 * @param type
	 * @return
	 */ 
	@SuppressWarnings("unchecked")
	public  <T> T  get(K key, HK hashKey,Class<T> type) {
		template.setConvertType(type);
		return  (T) get(key, hashKey);
	}
	public  <T> T  get(K key, HK hashKey,Class<T> type,DBExecutor<T> db) {
		return get(key, hashKey, type, db,null,null);
	}

	
	public HV get(K key, HK hashKey, DBExecutor<HV> db, Long timeout, TimeUnit unit) {
		HV v  = get(key, hashKey);
		if(v == null){
			v = db.execute(key,hashKey);
			if(v != null){
				put(key, hashKey, v);
				expire0(key, timeout, unit);
			}
		}
		return  v;
	}
	
	public  <T> T  get(K key, HK hashKey, Class<T> type, DBExecutor<T> db, Long timeout, TimeUnit unit) {
		T v  = get(key, hashKey,type);
		if(v == null){
			v = db.execute(key,hashKey);
			if(v != null){
				ops.put(key, hashKey, v);
				expire0(key,timeout,unit);
			}
		}
		return  v;
	}
	private void expire0(Object key,Long timeout, TimeUnit unit) {
		if(timeout != null){
			if(unit == null){
				unit = TimeUnit.SECONDS;
			}
			template.expire((K) key, timeout, unit);
		}
	}
	
	
	public void put(K key, HK hashKey, HV value, DBExecutor<HV> db, Long timeout, TimeUnit unit) {
		boolean needEx = false;
		if(timeout != null){
			if(unit == null){
				unit = TimeUnit.SECONDS;
			}
			needEx = ! template.hasKey(key);
		}
		put(key, hashKey, value);		
		if(needEx){
			template.expire(key, timeout, unit);
		}
		db.execute(key, hashKey, value);
	}
	
	
}
